package qr.server.admin;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.InputVerifier;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import qr.core.Game;
import qr.core.Location;
import qr.server.managers.TransactionGateway;

@SuppressWarnings("serial")
public class CreateGameScreen extends ApplicationScreen {
	
	private Game game;
	private DefaultListModel locationsModel = new DefaultListModel();

	private JPanel attributes;
	private JList locations;
	private JPanel actions;
	private JPanel locationActions;
	private JPanel gameActions;
	
	private JTextField name;
	private JFormattedTextField time;

	private JButton addLocation;
	private JButton editLocation;
	private JButton deleteLocation;
	
	private JButton confirm;
	private JButton viewLeaders;
	private JButton cancel;

	public CreateGameScreen(ApplicationWindow parent) {
		super(parent);
		
		this.setLayout(new BorderLayout());
		
		// Create panels
		this.attributes = new JPanel(new FlowLayout());
		this.locations = new JList();
		this.locations.setModel(locationsModel);
		locations.setBorder(BorderFactory.createTitledBorder("Locations"));
		this.actions = new JPanel(new GridLayout(2,1));
		this.locationActions = new JPanel(new FlowLayout());
		this.locationActions.setBorder(BorderFactory.createLineBorder(Color.BLACK));
		this.gameActions = new JPanel(new FlowLayout());
		
		// Set up panel components
		this.name = new JTextField(15);
		this.name.setInputVerifier(new InputLengthValidator(15));
		this.time = new JFormattedTextField();
		this.time.setColumns(5);
		this.time.setValue(new Integer(0));
		this.name.setFont(new Font("Helvetica", Font.PLAIN, 16));
		this.time.setFont(new Font("Helvetica", Font.PLAIN, 16));
		
		
		this.addLocation = new JButton("Add Location");
		this.addLocation.setIcon(new ImageIcon(this.getClass().getResource("/plus.png")));
		this.editLocation = new JButton("Edit Location");
		this.editLocation.setEnabled(false);
		this.deleteLocation = new JButton("Delete Location");
		this.deleteLocation.setIcon(new ImageIcon(this.getClass().getResource("/minus.png")));
		this.deleteLocation.setEnabled(false);
		
		this.confirm = new JButton("Save");
		this.confirm.setIcon(new ImageIcon(this.getClass().getResource("/Yes_check.png")));
		this.viewLeaders = new JButton("View Leaderboard");
		this.cancel = new JButton("Cancel");
		this.cancel.setIcon(new ImageIcon(this.getClass().getResource("/X_mark.png")));
		
		// Place components
		this.attributes.add(new JLabel("Game Name: "));
		this.attributes.add(this.name);
		this.attributes.add(new JLabel("Time Limit (minutes): "));
		this.attributes.add(this.time);

		this.locationActions.add(this.addLocation);
		this.locationActions.add(this.editLocation);
		this.locationActions.add(this.deleteLocation);
		this.gameActions.add(this.confirm);
		this.gameActions.add(this.viewLeaders);
		this.gameActions.add(this.cancel);
		this.actions.add(this.locationActions);
		this.actions.add(this.gameActions);
		
		this.add(this.attributes, BorderLayout.NORTH);
		this.add(this.locations, BorderLayout.CENTER);
		this.add(this.actions, BorderLayout.SOUTH);
		
		this.locations.addListSelectionListener(new ListSelectionListener() {
			@Override
			public void valueChanged(ListSelectionEvent e) {
				Location loc = (Location) locations.getSelectedValue();
				editLocation.setEnabled(loc != null ? true : false);
				deleteLocation.setEnabled(loc != null ? true : false);
			}
		});
		
		this.locations.addMouseListener(new MouseAdapter() {
		    public void mouseClicked(MouseEvent evt) {
		        if (evt.getClickCount() == 2) {
		    		Location loc = (Location) locations.getSelectedValue();
		        	switchTo("AddLocationScreen", new Object[]{game, loc});
		        }
		    }
		});
		
		this.addLocation.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				addLocationClicked(e);
			}
		});
		this.editLocation.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				editLocationClicked(e);
			}
		});
		this.deleteLocation.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				deleteLocationClicked(e);
			}
		});

		this.confirm.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				confirmClicked(e);
			}
		});
		this.viewLeaders.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				viewLeadersClicked(e);
			}
		});
		this.cancel.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				cancelClicked(e);
			}
		});
		
	}
	
	/**
	 * Constructor with received object
	 * 
	 * @param parent
	 * @param obj
	 */
	public CreateGameScreen(ApplicationWindow parent, Object[] objs) {
		this(parent);
		if(objs.length == 1 && objs[0] instanceof Game) {
			this.game = (Game) objs[0];
			
			// Update fields to reflect current game info
			this.name.setText(game.getGameName());
			this.time.setText(Integer.toString(game.getGameDuration()));
			List<Location> locs = game.getLocations();
			for(Location loc : locs) {
				this.locationsModel.addElement(loc);
			}
			
		} else {
			this.game = new Game();
			System.err.println("CreateGameScreen: Object received was not a Game.\n" +
					"Creating a new Game instead...");
		}
	}

	/**
	 * Handler for click event of the addLocation button.
	 * 
	 * @param e Event object
	 */
	private void addLocationClicked(ActionEvent e) {
		constructGameFromFields();
		switchTo("AddLocationScreen", new Object[]{game, new Location()});
	}
	/**
	 * Handler for click event of the editLocation button.
	 * 
	 * @param e Event object
	 */
	private void editLocationClicked(ActionEvent e) {
		Location loc = (Location) locations.getSelectedValue();
		if(loc != null)
			switchTo("AddLocationScreen", new Object[]{game, loc});
	}
	/**
	 * Handler for click event of the deleteLocation button.
	 * 
	 * @param e Event object
	 */
	private void deleteLocationClicked(ActionEvent e) {
		Location loc = (Location) locations.getSelectedValue();
		if(loc != null && JOptionPane.showConfirmDialog(this, "Delete selected location? This cannot be undone.", "Delete location?", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
			TransactionGateway.getInstance().startTransaction();
			game.removeLocation(loc);
			TransactionGateway.getInstance().endTransaction();
			TransactionGateway.getInstance().deleteLocation(loc.getId());
			locationsModel.remove(locations.getSelectedIndex());
		}
	}
	
	/**
	 * Handler for click event of the createGame button.
	 * 
	 * @param e Event object
	 */
	private void confirmClicked(ActionEvent e) {
		TransactionGateway db = TransactionGateway.getInstance();
		constructGameFromFields();
		if(!db.isManaged(game)) db.persist(game);
		switchTo("HomeScreen");
	}
	/**
	 * Handler for click event of the cancel button.
	 * 
	 * @param e Event object
	 */
	private void cancelClicked(ActionEvent e) {
		switchTo("HomeScreen");
	}
	
	/**
	 * Handler for click event of the viewLeaders button.
	 * 
	 * @param e Event object
	 */
	private void viewLeadersClicked(ActionEvent e) {
		switchTo("ManageLeaderboardScreen", new Object[]{game});
	}
	
	/**
	 * updates the game object using the information from the fields and locations list
	 */
	@SuppressWarnings("unchecked")
	private void constructGameFromFields() {
		TransactionGateway db = TransactionGateway.getInstance();
		if(db.isManaged(game)) db.startTransaction();
		
		game.setGameName(name.getText());
		game.setGameDuration(Integer.parseInt(time.getText()));
		Enumeration<Location> locsModel = (Enumeration<Location>) locationsModel.elements();
		ArrayList<Location> locs = new ArrayList<Location>();
		while(locsModel.hasMoreElements()) {
			locs.add(locsModel.nextElement());
		}
		game.setLocations(locs);
		
		if(db.isManaged(game)) db.endTransaction();
	}
}